      !< Módulo para definição das variáveis globais
      !> @todo Limpar as variáveis não utilizadas
      !> @todo Colocar algumas constantes como parameter
      !> @todo rever se esses parametros maxXXXX estao sendo usados em dimensionamento ainda
      MODULE globais

      implicit none
      integer, parameter:: maxNeq=1001*501 !< máximo número de nós do grid da simulação.
      integer, parameter:: maxNnz=5*maxNeq !< número máximo de elementos diferentes de zero na matriz do sistema do problema direto.
      integer, parameter:: maxNsource=150 !< número máximo de fontes.
      integer, parameter:: maxNrec=maxNsource !< número máximo de receptores

      complex*16, parameter :: imag = (0.,1.) !< unidade imaginária

      double precision, parameter :: Pi = 4.*atan(1.) !< número Pi





      integer :: maxiterLBFGS

! 	para a SuperLU : sistema do problema direto
      complex*16, dimension(:,:), allocatable ::f !< Fonte, lado direito do sistema do problema direto.

      complex*16, dimension(:), allocatable ::  values   !< Valores não nulos da matriz de impedância (transposta) armazenada no esquema CCS.
      integer, dimension(:), allocatable :: rowind !< Índice das linhas dos elements não nulos da matriz de impedância transposta.
      integer, dimension(:), allocatable :: colptr !< NNZ do primeiro elemento não nulo de cada coluna da matriz de impedância transposta .
      integer :: nnz=0 !< Número de elementos não nulos da matriz de impedância transposta.
      integer:: Neq !< Número de incógnitas / equações do sistema do problema direto. É igual ao número de nós da malha do problema direto.


!  inversao
      integer :: N !< Número de parâmetros/incógnitas do problema inverso. 

      integer :: metodo
      integer :: clust
      integer :: suav
      integer:: Nloops !< Número de loops no loop das frequências (esquema multiloop).
      integer:: kloop !< Contador de loops do esquema multiloops.

      complex*16, dimension(:), allocatable :: resid !< Vetor resíduo, dado pela diferença entre os dados sísmicos e os valores calculados.
      complex*16, dimension(:,:), allocatable :: residexpandido !< Resíduo expandido. !< Conjunto de Nsource vetores de ordem Neq cujos elementos não nulos são os referentes aos receptores e valem o conjugado do resíduo. 


      double precision, dimension(:), allocatable :: DX!< diferença entre o vetor de incógnitas atual e o da iteração anterior
      double precision :: Misfit !< Norma do vetor resíduo
      double precision, dimension(:), allocatable :: gradmisfit !< Gradiente da norma do resíduo.
      double precision, dimension(:), allocatable :: gradFobjetivo !< Gradiente da função objetivo, resíduo mais termo de regularização
      complex*16, dimension(:,:), allocatable :: JdeX !< Matriz Jacobiana, guarda as derivadas de u em relação às variáveis de otimização
      complex*16,dimension(:,:),allocatable :: deltaR !< Conjunto de Nrec vetores unitários. Cada coluna contém o valor 1 no noh do receptor correspondente. 


      real, dimension(:,:), allocatable  :: Hprec !< Matriz Hessiana JT*J cheia. Só para problemas pequenos.
      double precision, dimension(:), allocatable :: Hvalue!< Elementos não nulos da aproximação esparsa da Hessiana para ser usada como matriz de precondicionamento
      integer, dimension(:), allocatable :: Hrowind !< Índice das linhas dos elementos não nulos da Hessiana aproximada. Esquema CCS de armazenamento.    
      integer, dimension(:), allocatable :: Hcolind !< Índice das colunas dos elementos não nulos da Hessiana aproximada. Não faz parte do esquema de armazenamento, é apenas um vetor auxiliar. 
      integer, dimension(:), allocatable :: Hcolptr !< Guarda o nnz do primeiro elemento não nulo de cada coluna. Esquema CCS de armazenamento. 
      integer :: ioptH=0 
      integer :: nrhsH,ldyH,infoH
      integer*8 :: factorsH



      integer:: Hnnz !< Número de elementos não nulos da Hessiana aproximada.

      integer, dimension(:,:), allocatable :: depX !< Para cada incógnita do problema inverso, guarda os respectivos números dos nós da malha do problema direto. Dependência entre os nós da malha do problema direto e os nós da malha do problema inverso.
      integer :: sizedep !< Número máximo de nós do problema direto que depende de uma incógnita do problema inverso. Usado no dimensionamento da matriz depX.
      double precision, parameter :: cmin=100.d0 !< Velocidade de propagação mínima usada para limitar o espaço de busca, mapeando o problema de otimização com restrição em um problema de otimização sem restrição.
      double precision, parameter :: cmax=6900.d0 !< Velocidade de propagação máxima usada para limitar o espaço de busca, mapeando o problema de otimização com restrição em um problema de otimização sem restrição.

      double precision:: cminreal!< Variável auxiliar na criação de um modelo para simulação dos dados sísmicos. 

      double precision, dimension(:), allocatable:: Xref !<  Valores de referência para os parâmetros de otimização.
      double precision, dimension(:), allocatable:: Xn !< Valores das variáveis de otimização na n-ésima iteração.
      double precision, dimension(:), allocatable:: CXR !< Mapeamento dos parâmetros de referência em velocidade.
      double precision, dimension(:), allocatable:: CXN !< Mapeamento dos parâmetros da n-ésima iteração em velocidade.
      double precision, dimension(:), allocatable:: CX !<  Mapeamento dos parâmetros de otimização em velocidade.

      double precision :: errorelat!< erro relativo: raiz da razão entre o somatório das diferencas ao quadrado e o somatório do valor esperado ao quadrado
      double precision :: Fxn=0.0d0 !< Valor da função objetivo na n-ésima iteração.
      double precision :: lambdan=0.0d0 !< Valor do parâmetro de regularização na n-ésima ietaração.
      double precision :: lambdanaux=0.0d0 !< Valor auxiliar para o parâmetro de regularização.
      double precision :: betaTikho = 0.0d0 !< Parâmetro para relativizar a norma do resíduo e o termo de regularização de Tikhonov.  
      double precision :: qreg    !< Parâmetroda regularização da Equação 5.107 do Zhdanov  
      double precision :: Treg !< Termo de regularização.
      double precision, dimension(:), allocatable:: gradTreg!< Gradiente do termo de regularização em relação às variáveis de otimização.
      integer :: kReg !<  Tipo de regularizacao. Se kreg=0 --> sem regularizacao; Se kreg=1 --> regularização L2 Tikhonov; Se kreg=2 --> regularização L2 (Hu et al., 2009); Se kreg=3 --> weighted L2 regularization (Hu et al., 2009).

      integer :: iterant !< Número da iteracao anterior.
      integer :: iter !< Número da iteracao.

! 	informacoes do grid
      integer:: Nx!< Número de nós do grid do PD na direção x.
      integer:: Nz!< Número de nós do grid do PD na direção z.
      integer:: Nx0 !< Número de nós do grid do PI na direção x.
      integer:: Nz0 !< Número de nós do grid do PI na direção z.
      double precision :: Lx !< Largura do modelo da simulação, inclui camada de absorção, se houver.
      double precision :: Lz !< Profundidade do modelo da simulação, inclui camada de absorção, se houver.
      double precision :: Lx0 !< Largura original do modelo a ser invertido.
      double precision :: Lz0  !< Profundidade original do modelo a ser invertido.
      double precision :: delta !< Distância entre os nós da malha de diferenças finitas nas direções x e z.
      double precision :: deltaX0 !< Distância entre os nós da malha do PI na direção x.
      double precision :: deltaZ0 !< Distância entre os nós da malha do PI na direção z.

      double precision :: Cpml     !< Coeficiente do modelo de camada de absorção, determinada empiricamente (tentativa e erro).
      integer :: Npml     !< Número de nós de cada camada de absorção.
   

!     propriedades dos materiais
      double precision, dimension(:,:), allocatable:: b !< Buoyancy, inverso da massa específica.
      double precision, dimension(:,:), allocatable:: K !< Bulk modulus K=rho*c^2.
      double precision, dimension(:,:), allocatable:: rho !< Densidade (massa específica).
      double precision :: rhocte!< Valor da densidade escolhido pelo usuário no arquivo de entrada.
      double precision, dimension(:,:), allocatable:: c !< Velocidade de propagação.
      real, dimension(:,:), allocatable:: creal4 !< Velocidade de propagação truncada em real*4 para impressão em arquivo binário a ser plotado pelas rotinas do Seismic Unix.



      double precision:: gammax !< Parâmetro de amortecimento, direção x, diferente de zero somente dentro das camadas PML.    
      double precision:: gammaz !< Parâmetro de amortecimento, direção z, diferente de zero somente dentro das camadas PML.      
      complex*16, dimension(:), allocatable:: csix!< Função do amortecimento, direção x, é igual a 1 dentro do modelo e diferente de 1 dentro das camadas PML.
      complex*16, dimension(:), allocatable:: csiz !< Função do amortecimento, direção z, é igual a 1 dentro do modelo e diferente de 1 dentro das camadas PML.
      double precision, dimension(:,:), allocatable:: c0 !<Velocidade de propagação referente ao grid de incógnitas do PI.


      integer:: gruposSR !< Número de grupos de fontes e receptores correspondentes.	
      integer:: igsr !< Contador para o número de grupos de fontes e receptores.
      integer:: medidas !< Número total de dados sísmicos (ou medidas), de todos os grupos de fonte/receptor.


!     fonte
      double precision, dimension(:), allocatable :: St !< fonte no domínio do tempo
      complex*16, dimension(:), allocatable:: Sw !< Transformada de Fourier da wavelet no domínio espaço/tempo para o domínio espaço/frequência.
      double precision, dimension(:), allocatable:: omegas !< Frequências angulares usadas na transforma de Fourier da fonte.
      integer :: ntps !< amostragem, número de instantes de tempo por segundo
      integer :: nttotal !< número de instantes de tempo total

      integer, dimension(:), allocatable:: Nsource !< Número de fontes sísmicas (em cada grupo de fontes/receptores).
      integer :: NsourceSnap=3 !< Número de fontes para as quais serão feitos os snapshots. Por limitacao de memoria, não é possível fazer a transformada inversa da solução e gerar os snapshots e sismogramas para todas as fontes.
      integer :: ideltasnap !< De quantas em quantas fontes, a resposta no domínio da frequência em todo domínio é salva para fazer snapshots.
      integer :: Ntsnaps=30 !< Número de instantes de tempo para os snapshots.
      double precision :: dtsnaps !< intervalo de tempo entre snapshots

      double precision, dimension(:), allocatable :: xsource !< Coordenada x das fontes.
      double precision, dimension(:), allocatable :: zsource !< Coordenada z das fontes.
      integer, dimension(:,:), allocatable :: isource !< Número do nó na direção x das fontes.
      integer, dimension(:,:), allocatable :: jsource !< Número do nó na direção z das fontes.
      integer:: Nomega !< Número de frequências para a inversão (ou usadas na simulação). 
      integer :: escFreq !< Se escFreq=1--> o usuário informa na próxima liha do arquivo de dados as frequências escolhidas. Se  escfreq=2--> faz a transformada de Fourier usando as frequências calculadas automaticamente.
      integer:: kw  !< Contador de frequências
      integer:: kr  !< Contador de receptores
      integer:: ks  !< Contador de fontes
      integer:: kss !< Contador de fontes para snapshot

!  	receptores
      integer, dimension(:), allocatable :: Nrec !< Número de receptores (em cada grupo fontes/receptores).
      double precision, dimension(:), allocatable:: xreceiv!< Coordenada x dos receptores.
      double precision, dimension(:), allocatable:: zreceiv!< Coordenada z dos receptores.
      integer, dimension(:,:), allocatable:: ireceiv!< Número do nó na direção x dos receptores.
      integer, dimension(:,:), allocatable:: jreceiv!< Número do nó na direção z dos receptores.
      double precision :: fcorte !< Frequência de corte em Hz.
      double precision :: fpico !< Frequência de pico em Hz.
      double precision :: tp !< Tempo de disparo em segundos.
      double precision :: ampS !< Amplitude da fonte sísmica.
      double precision :: tf!< Tempo final de gravação nos receptores em segundos.
      
!     solucao
!       complex*16, dimension(:,:,:,:), allocatable:: P !Campo de pressao no dominio da frequencia P(i,j,kw,ks)
      complex*16, dimension(:,:,:,:), allocatable:: P !< Campo de pressão no domínio da frequência.
      real, dimension(:,:,:,:,:), allocatable:: Ptreal !< Campo de pressão no dominio do tempo.
!       real, dimension(:,:,:,:), allocatable:: Ptimag !<campo de pressao no dominio do tempo Ptimag(i,j,kt,ks)  mas kt, indice do intante tem que ser menor que kw para ser economico no armazenamento


      complex*16, dimension(:,:,:,:), allocatable:: Preceiv !< Campo de pressão, valores simulados, domínio da frequência, nos receptores. 
      complex*16, dimension(:,:,:,:), allocatable :: PreceivBARRA !< Campo de pressão, transformada dos dados sísmicos, nos receptores.     
!       double precision, dimension(:), allocatable  :: norm2Pbarra ! norma 2 ao quadrado do vetor de medidas para cada frequencia.
      double precision:: norm2Pbarra !< Quadrado da norma-2 do vetor de medidas para cada frequência.


      complex*16, dimension(:,:), allocatable:: Ptreceiv !< Campo de pressao no dominio do tempo nos receptores. 


      real, dimension(:,:), allocatable:: PtrecR !< Parte real do campo de pressão no dominio do tempo nos receptores, truncada em real*4, para plotagem dos sismogramas pelo SU.
      real, dimension(:,:), allocatable:: PtrecI !< Parte imaginária do campo de pressão no dominio do tempo nos receptores, truncada em real*4, para plotagem dos sismogramas pelo SU.

      integer :: iplot = 0 !< Contador de plotagens da imagem do campo de velocidade.
      double precision :: wbox=4.5!< Largura das plotagens do SU.

!       integer :: ietapa
      integer :: unitsol=20!< Unidade do arquivo binário para impressão do campo de velocidade em várias iterações.
      integer :: unitF=21!< Unidade do arquivo de texto que salva os valores da norma do resíduo do termo de regularização em cada avaliação.
      integer :: unitFgrad=22!< Unidade do arquivo de texto que salva os valores da norma do resíduo do termo de regularização em cada avaliação do gradiente.
      integer :: unitX=23!< Unidade do arquivo binário para impressão do campo de velocidade mais recente.

      integer :: unitBFGSlp=24!< unidade do arquivo de saída do LBFGS, variável LP na rotina lbfgs, se mudar aqui, tem que mudar a LP dentro de um common na lbfgs.f
      integer :: unitBFGSmp=25!< unidade do arquivo de saída do LBFGS, variável MP na rotina lbfgs, se mudar aqui, tem que mudar a LP dentro de um common na lbfgs.f








! lembrete dos formatos
! 
!  100  format(2i10,3E15.6)
!  101  format(3i10,'  (',E15.6,' , ',E15.6,' ) ')
!  102  format(4(E15.6))
!  150  format(//a450//)
!  151  format(//a390//)

      END MODULE globais